這個章節比較偏觀念,如淺複製及深複製的一些概念,我覺得是非常重要的重點。
首先是字串、數值、布林值的賦值
let a = "A";
let b = a;
a = "B";
console.log(a, b); // B,A
let c = 0;
let d = c;
c++;
console.log(c, d); // 1,0
let e = true;
let f = e;
e = !f;
console.log(e, f); // false,true
發現記憶體沒有A就創建一個A值並賦予記憶體位置
,再將g,h,i指向,A的記憶體位置
,再來找B,C都沒有,就創建B,C並賦予記憶體位置,再來h指向B記憶體位置,i指向C記憶體位置,最後將g+h=AB並賦予記憶體位置,g指向AB記憶體位置,接著g+i=ABC並賦予記憶體位置,g指向AB記憶體位置。
let g = "A";
let h = "A";
let i = "A";
h = "B", i = "C", g += h, g += i;
console.log(g, h, i); //ABC , B ,C
接著是做關於陣列的複製。
const players = ['Wes', 'Sarah', 'Ryan', 'Poppy'];
let player2 = players;
player2[0] = "jojo";
console.log(players, player2);
[0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"] [0: "jojo",1: "Sarah",2: "Ryan",3: "Poppy"]
發現這並不是我們所要得複製,他們都對應到同一個陣列,所以利用以下幾種方法,可達到互不影響的複製。
法1:slice()方法,利用slice可達到複製,因為slice會額外再產生一個新的陣列。
let player2 = players.slice();
player2[0] = "jojo";
console.log(players, player2);
(4) ["Wes", "Sarah", "Ryan", "Poppy"] (4) ["jojo", "Sarah", "Ryan", "Poppy"]
法2:concat()
方法,被用來合併兩個或多個陣列。此方法不會改變現有的陣列,會回傳呼叫者陣列本身
,也就是與players的值合併後的空陣列。
let player2 = [].concat(players);
player2[0] = "jojo";
console.log(players, player2);
法3:解構賦值,將players中的值拆分出來,在合併至player2,回傳一個新的陣列。
let player2 = [...players];
player2[0] = "jojo";
console.log(players, player2);
再來是配合呼叫函數所產生的陣列複製。
function createObj(name) {
return {
//name:name
name
};
}
let pr1 = createObj("johnny");
let pr2 = createObj("lisa");
let pr3 = createObj("iggy");
let gr1 = [pr1, pr2, pr3];
let gr2 = gr1.slice();
// 由於gr2[0]值為pr1,所以他會去改變gr2[0].name,也就是pr1的值,那我再次獲取gr1,它裡面的pr1也會是改變後的值。
gr2[0].name = "momo";
console.log(gr1, gr2); // (3) ["momo", "lisa", "iggy"]
// 但如果改為這樣,可發現兩者已互不影響,因為記憶體發現我們的記憶體中並無momo這個值,所以他會創建一個momo的值,並給予他一個記憶體空間,而後我們gr2[0](也就是gr2的pr1)就會指向他,並不影響。
gr2[0] = "momo";
console.log(gr1, gr2); // (3) ["johnny", "lisa", "iggy"] (3) ["momo", "lisa", "iggy"]
接下來是物件之間的複製與賦值。
let person = {
name: 'Wes Bos',
age: 80
};
let p1 = person;
// 查看記憶體無XXX後,創建一個XXX的值並賦予記憶體空間,接著person在指向他,而與p1互不影響。
person = "XXX";
console.log(person, p1); // XXX,{...}
// 前面步驟與上面一樣,不同的是會改變person.name的值也就是0x1的name,因此p1也會受影響,因為p1指向的也是person所指向的0x1。
person.name = "XXX";
console.log(person, p1); // {XXX...},{XXX...}
將物件x,y合併後,賦予z,會發現後者的重複的name可以覆蓋前者的。
let x = {
name: "bogi",
age: 87
};
let y = {
name: "dandy"
};
let z = Object.assign(x, y);
console.log(z); // {name: "dandy", age: 87}
如果我們今天在物件新增一個函數
,然後以kk複製他並一樣先字串化,然後再轉回obj化,會發現再以kk呼叫就會報錯,因為經stringify,function會被lose掉
。
let k = {
name: "eva",
age: 22,
eat: function () {
console.log("amazing");
}
};
let kk = JSON.parse(JSON.stringify(k));
// k.eat() // amazing
// kk.eat() // Uncaught TypeError: kk.eat is not a function at <anonymous>:1:4
如果今天我們的物件不含函
數,那麼利用JSON.parse(JSON.stringify(wes)),就可以達到deep copy
,但如果有就無法。
const wes = {
name: 'Wes',
age: 100,
social: {
twitter: '@wesbos',
facebook: 'wesbos.developer'
}
};
const dev = Object.assign({}, wes);
// 第一題
// 互不影響
dev.social = null;
console.log(wes); // 不變 {twitter...};
// 第二題
dev.social.facebook = null;
console.log(wes.social); // {twitter:..., facebook:null}
const dev3 = JSON.parse(JSON.stringify(wes));
第一題
第二題
第三題:
首先將wes(0x6)的資料,經由stringify將0x6拿出來,並賦予一個新的記憶體空間0x8,再來經過parse,將0x5的資料拿出來(因為0x5為物件(或陣列或函數)資料就會重新賦予記憶體空間)0x9,而後重新創建一個記憶體空間0x10讓wes3指向他。